/**
 * @class 自定义天空盒实体
 * @author DuskyHuang 圣子
*/

import { smoothstep } from 'algorithms';
import { _decorator, Component, renderer, MeshRenderer, Color, IVec3Like, Vec4 } from 'cc';
import { core, Notifications } from 'cfw';
import { constStars, cosmos, visit } from 'proxies';
const { ccclass, property } = _decorator;

@ccclass('cocosmos.skybox-cube')
export class SkyboxCube extends Component {

    protected onLoad(): void {
        core.on(Notifications.Time.TICK, this.onTick, this);
        this._materials = this.getComponentsInChildren(MeshRenderer).map(mesh => mesh.getMaterialInstance(0));
        this._passes0 = this._materials.map(mat => mat.passes[0]);
        /** discard color to change skybox, use color-scale */
        // this._handles = this._passes0.map(pass => pass.getHandle('mainColor'));
        this._handles = this._passes0.map(pass => pass.getHandle('colorScaleAndCutoff'));
    }

    private _materials: renderer.MaterialInstance[] = [];
    private _passes0: renderer.Pass[] = [];
    private _handles: handle[] = [];

    @property
    private _luminance: num.ratio = 1;

    @property
    public get luminance(): num.ratio { return this._luminance; }
    public set luminance(arg: num.ratio) { this._luminance = arg; }

    @property
    private _color: Color = Color.WHITE.clone();

    @property
    private _scale: Vec4 = new Vec4;

    @property private _r: num.ratio = 1;
    @property private _g: num.ratio = 1;
    @property private _b: num.ratio = 1;

    @property
    public get r(): num.ratio { return this._r; }
    public set r(arg: num.ratio) { this._r = arg; }

    @property
    public get b(): num.ratio { return this._b; }
    public set b(arg: num.ratio) { this._b = arg; }

    @property
    public get g(): num.ratio { return this._g; }
    public set g(arg: num.ratio) { this._g = arg; }

    public get rotY(): num.deg { return this.node.eulerAngles.y; }
    public set rotY(arg: num.deg) { const { x, y, z } = this.node.eulerAngles; this.node.setRotationFromEuler(x, arg, z); }

    public setRotation(euler: IVec3Like): this {
        this.node.setWorldRotationFromEuler(euler.x, euler.y, euler.z);
        return this;
    }

    public addRotY(add: num.deg): this {
        const { x, y, z } = this.node.eulerAngles; this.node.setRotationFromEuler(x, y + add, z);
        return this;
    }

    protected update(): void {
        const { _r, _g, _b, _luminance: l } = this;
        /** discard color to change skybox, use color-scale */
        // const alpha = _luminance * 255;
        // this._color.set(_r * alpha, _g * alpha, _b * alpha, 255);
        this._scale.set(_r * l, _g * l, _b * l);
        this._passes0.forEach((pass0, idx) => {
            pass0.setUniform(this._handles[idx], this._scale);
        });
    }

    protected onTick(): void {
        const { showStars } = constStars, { pow10 } = cosmos;
        const [FROM, TO] = STARS_BOX_RANG;
        const illum = showStars ? smoothstep(TO, FROM, pow10) : 0;
        if (illum > 0) {
            this.node.active = true;
            this.luminance = illum;
        } else this.node.active = false;
        /** discard cocos skybox background, use custom skybox */
        // this.scene.globals.ambient.skyIllum = illum;
        // const disabled = illum <= 0;
        // this.deepSkyCamera.clearFlags = disabled ? Camera.ClearFlag.SOLID_COLOR : Camera.ClearFlag.SKYBOX;
        // this.scene.globals.skybox.enabled = !disabled;
    }
}
const STARS_BOX_RANG: vec2<pow10> = [-3, 0];